Skip to content

Vue 2:虚拟 DOM 与 diff

同一话题集中阐述,便于对照阅读。


一、为何需要虚拟 DOM 与 diff

直接操作真实 DOM(创建、删除、移动)成本高,易触发重排/重绘
Vue 先在内存维护 VNode 树,数据变更后生成新 VNode,与旧 VNodediff,只对差异部分 patch 到真实 DOM,从而减少 DOM 操作次数

核心:不是为了一句「快」,而是为了可控的批量更新与跨平台抽象


二、虚拟 DOM 是什么

VNode 是用 JS 对象描述节点类型、属性、子节点等的树形结构;首次渲染由渲染函数生成 VNode,再 patch 成真实 DOM。

好处归纳

  • 性能:合并更新、最小化 DOM 写入。
  • 跨平台:同一套 VNode 思路可对接不同渲染后端。
  • 开发体验:声明式模板,多数场景不必手写 DOM API。

工作流程

  1. 渲染函数执行 → 新 VNode 树
  2. patch(oldVnode, vnode):比对新旧差异。
  3. 将差异应用到真实 DOM。

与「只用新 VNode 全量替换真实 DOM」对比

若每次整树替换真实 DOM,稍有改动也代价巨大;diff 的意义在于复用仍有效的真实节点,只做增量变更。


三、Vue 2 diff 策略要点

关键词

  • 同层比较:不大面积跨层级对比(跨层移动常被视为删除+新建)。
  • 双端(双指针):子节点为数组时,从首尾向中间四种配对尝试复用。
  • key:列表项身份标识,决定能否移动而非重建。

sameVnode / patchVnode

  • 先判断是否 sameVnode(标签、key、注释节点等语义一致)。
  • 不同则替换;相同则 patchVnode,更新属性与子节点。

双端比较直觉

四个索引:旧头、旧尾、新头、新尾;四种快捷匹配失败后再用 key → 下标映射找可复用节点;剩余节点删除或新建。

复杂度

粗暴的两棵树比对可达更高阶;Vue 2 通过同层 + key + 双端把常见列表场景控制在近似 O(n)(n 为参与比较的节点规模)。


四、diff 时机

  • 首次渲染:生成 VNode 并挂载,不与「上一帧」比对(无旧树)。
  • 更新:响应式触发组件渲染函数 → 新 VNode上一次保留的旧 VNode比对。

与异步队列的关系

多次数据修改可能在一次 nextTick 内合并为一次渲染与 patch;patch 过程中仍是递归对比并逐步更新 DOM(与「队列合并」不在同一层级)。


五、Vue 2 vs React diff(简述)

常见对比:Vue 2 列表双端试探 vs React 基于 key 的映射与单向扫描;各有取舍,可从「减少 DOM 移动」角度回答即可。


六、vue2 diff 算法.md 精简对照

Vue 2Vue 3React
列表思路双端比较最长递增子序列 等优化单向扫描 + key 映射

详情见 Vue 3 合并文档中的跨框架对比章节。


七、列表优化要点

  • 稳定唯一 key(如业务 id)。
  • 避免 v-for 同行使用 v-if(Vue 2 尤其吃亏)。
  • 长列表:分页、虚拟滚动。
  • 大块静态内容:减少无谓的响应式拆分(与编译优化相关主要在 Vue 3)。

下一章:组件通信·缓存·Vuex·权限